#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>

// 服务器配置
#define SERVER_IP "192.168.2.77"
#define SERVER_PORT 60000

#define FILENAME "users.txt"
#define ACCOUNT_LENGTH 10
#define MAX_ATTEMPTS 100

// 用户信息结构体
struct account_info
{
    char a[ACCOUNT_LENGTH + 1];     // 账号
    char user_name[30];             // 用户名
    char password[30];              // 密码
    struct sockaddr_in client_addr; // 地址结构体
};

// 登录信息结构体
struct login_info
{
    char identifier[30]; // 用户名或账号
    char password[30];
};

// 在线用户节点
struct online_user
{
    char account[ACCOUNT_LENGTH + 1];
    char username[30];
    int socket_fd;
    struct sockaddr_in addr;
    struct online_user *next;
};

// 用户连接信息
struct user_info
{
    int socket_fd;
    struct sockaddr_in client_addr;
};

// 全局互斥锁
pthread_mutex_t file_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t online_mutex = PTHREAD_MUTEX_INITIALIZER;

// 全局在线用户列表
struct online_user *online_list = NULL;

// 添加在线用户
void add_online_user(const char *account, const char *username, int socket_fd, struct sockaddr_in addr)
{
    pthread_mutex_lock(&online_mutex);

    struct online_user *new_user = malloc(sizeof(struct online_user));
    if (!new_user)
    {
        perror("内存分配失败");
        pthread_mutex_unlock(&online_mutex);
        return;
    }

    strncpy(new_user->account, account, ACCOUNT_LENGTH);
    strncpy(new_user->username, username, 29);
    new_user->socket_fd = socket_fd;
    new_user->addr = addr;
    new_user->next = online_list;
    online_list = new_user;

    pthread_mutex_unlock(&online_mutex);
}

// 移除在线用户
void remove_online_user(int socket_fd)
{
    pthread_mutex_lock(&online_mutex);

    struct online_user **ptr = &online_list;
    while (*ptr != NULL)
    {
        if ((*ptr)->socket_fd == socket_fd)
        {
            struct online_user *temp = *ptr;
            *ptr = (*ptr)->next;
            free(temp);
            break;
        }
        ptr = &(*ptr)->next;
    }

    pthread_mutex_unlock(&online_mutex);
}

// 获取在线用户列表字符串
char *get_online_users()
{
    pthread_mutex_lock(&online_mutex);

    // 计算所需缓冲区大小
    int size = 10; // "ONLINE:"
    struct online_user *current = online_list;
    while (current != NULL)
    {
        size += strlen(current->account) + strlen(current->username) + 3; // 账号,用户名 + 逗号 + 冒号
        current = current->next;
    }

    // 分配内存
    char *result = malloc(size);
    if (!result)
    {
        perror("内存分配失败");
        pthread_mutex_unlock(&online_mutex);
        return NULL;
    }

    // 构建列表
    strcpy(result, "ONLINE:");
    current = online_list;
    while (current != NULL)
    {
        strcat(result, current->account);
        strcat(result, ",");
        strcat(result, current->username);

        if (current->next != NULL)
        {
            strcat(result, ":");
        }

        current = current->next;
    }

    pthread_mutex_unlock(&online_mutex);
    return result;
}

// 查找在线用户
struct online_user *find_online_user(const char *account)
{
    pthread_mutex_lock(&online_mutex);

    struct online_user *current = online_list;
    while (current != NULL)
    {
        if (strcmp(current->account, account) == 0)
        {
            pthread_mutex_unlock(&online_mutex);
            return current;
        }
        current = current->next;
    }

    pthread_mutex_unlock(&online_mutex);
    return NULL;
}

// 检查账号是否唯一
bool is_account_unique(const char *account)
{
    pthread_mutex_lock(&file_mutex);

    FILE *fp = fopen(FILENAME, "r");
    if (!fp)
    {
        pthread_mutex_unlock(&file_mutex);
        return true;
    }

    char line[256];
    bool unique = true;

    while (fgets(line, sizeof(line), fp))
    {
        char saved_account[ACCOUNT_LENGTH + 1];
        if (sscanf(line, "%10[^,]", saved_account) == 1)
        {
            if (strcmp(saved_account, account) == 0)
            {
                unique = false;
                break;
            }
        }
    }

    fclose(fp);
    pthread_mutex_unlock(&file_mutex);
    return unique;
}

// 生成唯一账号
bool generate_unique_account(int socket_fd, char *account_out)
{
    int attempts = 0;
    char account[ACCOUNT_LENGTH + 1] = {0};

    do
    {
        for (int i = 0; i < ACCOUNT_LENGTH; i++)
        {
            account[i] = '0' + rand() % 10;
        }
        account[ACCOUNT_LENGTH] = '\0';

        if (is_account_unique(account))
        {
            if (send(socket_fd, account, ACCOUNT_LENGTH + 1, 0) < 0)
            {
                perror("发送账号失败");
                return false;
            }
            strcpy(account_out, account);
            return true;
        }

        attempts++;
    } while (attempts < MAX_ATTEMPTS);

    const char *error_msg = "无法生成唯一账号";
    send(socket_fd, error_msg, strlen(error_msg), 0);
    return false;
}

// 保存用户信息
void save_user_info(const char *account, const char *username, const char *password)
{
    pthread_mutex_lock(&file_mutex);

    FILE *fp = fopen(FILENAME, "a");
    if (!fp)
    {
        perror("无法打开用户文件");
        pthread_mutex_unlock(&file_mutex);
        return;
    }

    fprintf(fp, "%s,%s,%s\n", account, username, password);
    fclose(fp);

    pthread_mutex_unlock(&file_mutex);
}

// 验证登录信息
int verify_login(const struct login_info *login_data, char *account_out, char *username_out)
{
    pthread_mutex_lock(&file_mutex);

    FILE *fp = fopen(FILENAME, "r");
    if (!fp)
    {
        pthread_mutex_unlock(&file_mutex);
        return -1;
    }

    char line[256];
    int result = 1; // 默认登录失败

    while (fgets(line, sizeof(line), fp))
    {
        char saved_account[ACCOUNT_LENGTH + 1];
        char saved_username[30];
        char saved_password[30];

        if (sscanf(line, "%10[^,],%29[^,],%29s", saved_account, saved_username, saved_password) == 3)
        {
            if (strcmp(login_data->identifier, saved_account) == 0 ||
                strcmp(login_data->identifier, saved_username) == 0)
            {
                printf("Login successful%s,%s\n",login_data->password, saved_password);
                if (strcmp(login_data->password, saved_password) == 0)
                {
                    strcpy(account_out, saved_account);
                    strcpy(username_out, saved_username);
                    result = 0; // 登录成功
                    break;
                }
            }
        }
    }

    fclose(fp);
    pthread_mutex_unlock(&file_mutex);
    return result;
}

// 处理客户端数据
void *recv_client_info(void *arg)
{
    struct user_info cli_info = *(struct user_info *)arg;
    int socket_fd = cli_info.socket_fd;
    char *ip = inet_ntoa(cli_info.client_addr.sin_addr);
    int port = ntohs(cli_info.client_addr.sin_port);
    char current_account[ACCOUNT_LENGTH + 1] = {0};
    char current_username[30] = {0};

    char buf[1024] = {0};
    char generated_account[ACCOUNT_LENGTH + 1] = {0};
    struct account_info acc_info;
    struct login_info login_data;

    enum
    {
        NORMAL,
        WAITING_FOR_REG_INFO,
        WAITING_FOR_LOGIN_INFO
    } state = NORMAL;

    printf("客户端连接: [%s][%d]\n", ip, port);

    while (1)
    {
        printf("等待客户端数据...\n");
        memset(buf, 0, sizeof(buf));
        int ret = recv(socket_fd, buf, sizeof(buf) - 1, 0);
        printf("接收到数据: %s\n", buf);

        if (ret < 0)
        {
            perror("recv失败");
            break;
        }
        if (ret == 0)
        {
            printf("客户端断开连接[%s][%d]\n", ip, port);
            break;
        }

        buf[ret] = '\0';

        printf("接收到数据: %d,%d\n", state,NORMAL);
        if (state == NORMAL)
        {

            if (strcmp(buf, "REGISTER") == 0)
            {
                printf("收到注册请求[%s][%d]\n", ip, port);
                if (generate_unique_account(socket_fd, generated_account))
                {
                    state = WAITING_FOR_REG_INFO;
                }
            }
            else if (strcmp(buf, "LOGIN") == 0)
            {
                printf("收到登录请求[%s][%d]\n", ip, port);
                state = WAITING_FOR_LOGIN_INFO;
            }
            else if (strcmp(buf, "LIST") == 0)
            {
                printf("收到在线用户列表请求[%s][%d]\n", ip, port);
                char *online_users = get_online_users();
                if (online_users)
                {
                    send(socket_fd, online_users, strlen(online_users), 0);
                    free(online_users);
                }
            }
            else if (strncmp(buf, "PRIVATE:", 8) == 0)
            {
                // 格式: PRIVATE:接收方账号:消息内容
                char recipient[ACCOUNT_LENGTH + 1] = {0};
                char message[256] = {0};

                if (sscanf(buf + 8, "%10[^:]:%255[^\n]", recipient, message) == 2)
                {
                    struct online_user *target = find_online_user(recipient);
                    if (target)
                    {
                        char formatted_msg[300];
                        snprintf(formatted_msg, sizeof(formatted_msg), "PRIVATE:%s:%s", current_account, message);
                        send(target->socket_fd, formatted_msg, strlen(formatted_msg), 0);
                        send(socket_fd, "消息已发送", 12, 0);
                    }
                    else
                    {
                        send(socket_fd, "用户不在线", 12, 0);
                    }
                }
            }
            else
            {
                // 广播消息给所有在线用户
                char broadcast_msg[1024];
                snprintf(broadcast_msg, sizeof(broadcast_msg), "[%s]: %s", current_username, buf);

                pthread_mutex_lock(&online_mutex);
                struct online_user *current = online_list;
                while (current != NULL)
                {
                    if (current->socket_fd != socket_fd)
                    {
                        send(current->socket_fd, broadcast_msg, strlen(broadcast_msg), 0);
                    }
                    current = current->next;
                }
                pthread_mutex_unlock(&online_mutex);
            }
        }
        else if (state == WAITING_FOR_REG_INFO)
        {
            if (ret == sizeof(struct account_info))
            {
                memcpy(&acc_info, buf, sizeof(struct account_info));

                if (strlen(acc_info.a) == ACCOUNT_LENGTH)
                {
                    save_user_info(acc_info.a, acc_info.user_name, acc_info.password);
                    char success_msg[100];
                    snprintf(success_msg, sizeof(success_msg), "注册成功! 账号: %s, 用户名: %s",
                             acc_info.a, acc_info.user_name);
                    send(socket_fd, success_msg, strlen(success_msg), 0);
                }
                else
                {
                    send(socket_fd, "无效的账号格式", 15, 0);
                }
                state = NORMAL;
            }
            else
            {
                printf("注册信息不完整，收到%d字节\n", ret);
            }
        }
        else if (state == WAITING_FOR_LOGIN_INFO)
        {
            if (ret == sizeof(struct login_info))
            {
                memcpy(&login_data, buf, sizeof(struct login_info));
                char account[ACCOUNT_LENGTH + 1] = {0};
                char username[30] = {0};

                int login_result = verify_login(&login_data, account, username);
                if (login_result == 0)
                {
                    strcpy(current_account, account);
                    strcpy(current_username, username);

                    // 添加到在线用户列表
                    add_online_user(account, username, socket_fd, cli_info.client_addr);

                    // 发送登录成功消息
                    char success_msg[100];
                    snprintf(success_msg, sizeof(success_msg), "LOGIN_SUCCESS:%s:%s", username, account);
                    send(socket_fd, success_msg, strlen(success_msg), 0);
                    printf("用户 %s:%s 登录成功\n", username, account);

                    // 发送在线用户列表
                    char *online_users = get_online_users();
                    if (online_users)
                    {
                        send(socket_fd, online_users, strlen(online_users), 0);
                        free(online_users);
                    }
                }
                else
                {
                    send(socket_fd, "登录失败: 用户名或密码错误", 28, 0);
                }
                state = NORMAL;
            }
            else
            {
                printf("登录信息不完整，收到%d字节\n", ret);
            }
        }
    }

    // 客户端断开连接，从在线列表移除
    remove_online_user(socket_fd);
    close(socket_fd);
    return NULL;
}

int main(int argc, char **argv)
{
    srand(time(NULL));

    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd < 0)
    {
        perror("socket创建失败");
        return -1;
    }

    int optval = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

    if (bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("bind失败");
        close(socket_fd);
        return -1;
    }
    printf("服务器已启动: %s:%d\n", SERVER_IP, SERVER_PORT);

    if (listen(socket_fd, 20) < 0)
    {
        perror("listen失败");
        close(socket_fd);
        return -1;
    }

    while (1)
    {
        struct sockaddr_in client_addr;
        socklen_t addr_len = sizeof(client_addr);
        int socket_client = accept(socket_fd, (struct sockaddr *)&client_addr, &addr_len);

        if (socket_client < 0)
        {
            perror("accept失败");
            continue;
        }

        char *ip = inet_ntoa(client_addr.sin_addr);
        int port = ntohs(client_addr.sin_port);
        printf("新的客户端: [%s][%d]\n", ip, port);

        struct user_info cli_info;
        cli_info.socket_fd = socket_client;
        cli_info.client_addr = client_addr;

        pthread_t tid;
        if (pthread_create(&tid, NULL, recv_client_info, (void *)&cli_info) != 0)
        {
            perror("线程创建失败");
            close(socket_client);
        }
        else
        {
            pthread_detach(tid);
        }
    }

    close(socket_fd);
    return 0;
}